package edu.mse.camel.client.whiteboard.gef.ui.editor;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.gef.palette.CombinedTemplateCreationEntry;
import org.eclipse.gef.palette.ConnectionCreationToolEntry;
import org.eclipse.gef.palette.MarqueeToolEntry;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteDrawer;
import org.eclipse.gef.palette.PaletteEntry;
import org.eclipse.gef.palette.PaletteGroup;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PaletteSeparator;
import org.eclipse.gef.palette.PanningSelectionToolEntry;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite.FlyoutPreferences;
import org.eclipse.jface.preference.IPreferenceStore;

import edu.mse.camel.client.whiteboard.gef.ui.WhiteBoardUtil;
import edu.mse.camel.client.whiteboard.gef.ui.WhiteboardPlugin;
import edu.mse.camel.client.whiteboard.gef.ui.freehandwriting.FreeHandwritingToolEntry;
import edu.mse.camel.client.whiteboard.gef.whiteboard.Connection;
import edu.mse.camel.client.whiteboard.gef.whiteboard.EllipticalShape;
import edu.mse.camel.client.whiteboard.gef.whiteboard.RectangularShape;
import edu.mse.camel.client.whiteboard.gef.whiteboard.StickyNote;

/**
 * Utility class that can create a GEF Palette.
 * @see #createPalette() 
 * @author darpan
 */
public final class WhiteboardEditorPaletteFactory {

	/** Preference ID used to persist the palette location. */
	private static final String PALETTE_DOCK_LOCATION = "ShapesEditorPaletteFactory.Location";
	/** Preference ID used to persist the palette size. */
	private static final String PALETTE_SIZE = "ShapesEditorPaletteFactory.Size";
	/** Preference ID used to persist the flyout palette's state. */
	private static final String PALETTE_STATE = "ShapesEditorPaletteFactory.State";

	/** Create the "Shapes" drawer. */
	private static PaletteContainer createShapesDrawer() {
		PaletteDrawer componentsDrawer = new PaletteDrawer("Shapes");

		CombinedTemplateCreationEntry component = new CombinedTemplateCreationEntry(
				"Ellipse", 
				"Create an elliptical shape", 
				EllipticalShape.class,
				new CreationFactory() {
					public Object getNewObject() { return WhiteboardModelManager.getFactory().createEllipticalShape(); }
					public Object getObjectType() { return null; }
				},
				WhiteboardPlugin.getImageDescriptor("icons/ellipse16.gif"),
				WhiteboardPlugin.getImageDescriptor("icons/ellipse24.gif"));
		componentsDrawer.add(component);

		component = new CombinedTemplateCreationEntry(
				"Rectangle",
				"Create a rectangular shape", 
				RectangularShape.class,
				new CreationFactory() {
					public Object getNewObject() { return WhiteboardModelManager.getFactory().createRectangularShape(); }
					public Object getObjectType() { return null; }
				},
				WhiteboardPlugin.getImageDescriptor("icons/rectangle16.gif"),
				WhiteboardPlugin.getImageDescriptor("icons/rectangle24.gif"));
		componentsDrawer.add(component);

		component = new CombinedTemplateCreationEntry(
				"StickyNote",
				"Create a sticky note", 
				StickyNote.class,
				new CreationFactory() {
					public Object getNewObject() { return WhiteboardModelManager.getFactory().createStickyNote(); }
					public Object getObjectType() { return null; }
				},
				WhiteboardPlugin.getImageDescriptor("icons/sticky_note16.gif"),
				WhiteboardPlugin.getImageDescriptor("icons/sticky_note.gif24.gif"));
		componentsDrawer.add(component);

		return componentsDrawer;
	}

	/**
	 * Creates the PaletteRoot and adds all palette elements.
	 * Use this factory method to create a new palette for your graphical editor.
	 * @return a new PaletteRoot
	 */
	public static PaletteRoot createPalette() {
		PaletteRoot palette = new PaletteRoot();
		palette.add(createToolsGroup(palette));
		palette.add(createFreeHandDrawingDrawer(palette));
		palette.add(createShapesDrawer());
		return palette;
	}

	private static PaletteEntry createFreeHandDrawingDrawer(PaletteRoot palette) {
		PaletteDrawer freeHandDrawer = new PaletteDrawer("Markers");

		freeHandDrawer.add(
				new FreeHandwritingToolEntry(
						"My Color Marker", 
						"Sketch in my own color", 
						WhiteBoardUtil.createColorFromRGB(WhiteBoardUtil.getMyColor())));
		
		freeHandDrawer.add(
				new FreeHandwritingToolEntry(
						"Black Marker", 
						"Sketch in Black", 
						ColorConstants.black));
		
		freeHandDrawer.add(
				new FreeHandwritingToolEntry(
						"Red marker", 
						"Sketch in Red", 
						ColorConstants.red));
		
		freeHandDrawer.add(
				new FreeHandwritingToolEntry(
						"Blue marker", 
						"Sketch in Blue", 
						ColorConstants.blue));
		
		freeHandDrawer.add(
				new FreeHandwritingToolEntry(
						"Green marker", 
						"Sketch in Green", 
						ColorConstants.green));
		
		return freeHandDrawer;
	}

	/**
	 * Return a FlyoutPreferences instance used to save/load the preferences of a flyout palette.
	 */
	static FlyoutPreferences createPalettePreferences() {
		return new FlyoutPreferences() {
			private IPreferenceStore getPreferenceStore() {
				return WhiteboardPlugin.getDefault().getPreferenceStore();
			}
			public int getDockLocation() {
				return getPreferenceStore().getInt(PALETTE_DOCK_LOCATION);
			}
			public int getPaletteState() {
				return getPreferenceStore().getInt(PALETTE_STATE);
			}
			public int getPaletteWidth() {
				return getPreferenceStore().getInt(PALETTE_SIZE);
			}
			public void setDockLocation(int location) {
				getPreferenceStore().setValue(PALETTE_DOCK_LOCATION, location);
			}
			public void setPaletteState(int state) {
				getPreferenceStore().setValue(PALETTE_STATE, state);
			}
			public void setPaletteWidth(int width) {
				getPreferenceStore().setValue(PALETTE_SIZE, width);
			}
		};
	}

	/** Create the "Tools" group. */
	private static PaletteContainer createToolsGroup(PaletteRoot palette) {
		PaletteGroup toolGroup = new PaletteGroup("Tools");

		// Add a selection tool to the group
		ToolEntry tool = new PanningSelectionToolEntry();
		toolGroup.add(tool);
		palette.setDefaultEntry(tool);

		// Add a marquee tool to the group
		toolGroup.add(new MarqueeToolEntry());

		// Add a (unnamed) separator to the group
		toolGroup.add(new PaletteSeparator());

		// Add (solid-line) connection tool 
		tool = new ConnectionCreationToolEntry(
				"Solid connection",
				"Create a solid-line connection",
				new CreationFactory() {
					public Object getNewObject() { return null; }
					// see ShapeEditPart#createEditPolicies() 
					// this is abused to transmit the desired line style 
					public Object getObjectType() { return Connection.SOLID; }
				},
				WhiteboardPlugin.getImageDescriptor("icons/connection_s16.gif"),
				WhiteboardPlugin.getImageDescriptor("icons/connection_s24.gif"));
		toolGroup.add(tool);

		// Add (dashed-line) connection tool
		tool = new ConnectionCreationToolEntry(
				"Dashed connection",
				"Create a dashed-line connection",
				new CreationFactory() {
					public Object getNewObject() { return null; }
					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style 
					public Object getObjectType() { return Connection.DASHED; }
				},
				WhiteboardPlugin.getImageDescriptor("icons/connection_d16.gif"),
				WhiteboardPlugin.getImageDescriptor("icons/connection_d24.gif"));
		
		toolGroup.add(tool);
		
		return toolGroup;
	}

	/** Utility class. */
	private WhiteboardEditorPaletteFactory() {
		// Utility class
	}

}
